package com.autotest.sync.utils;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.concurrent.TimeUnit;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

/**
 * 执行本地命令,均有超时限制
 * 
 * @author thomas.ning
 * @version 2016年5月6日 上午10:45:50
 */
public class SystemCmdUtil {
	public static Logger logger = LogManager.getLogger(SystemCmdUtil.class
			.getSimpleName());
	
	/**
	 * 执行命令并返回结果
	 * 
	 * @param cmd
	 * @return
	 */
	public static String rexec(String cmd) {
		return rexec(cmd, null);
	}
	
	public static String rexec(String cmd, String dir) {
		return rexec(cmd, dir, 2*60);
	}
	
	/**
	 * 执行命令并返回结果, 指定执行命令目录,限定超时值，单位秒
	 * @param cmd
	 * @param dir
	 * @param timeOut
	 * @return
	 */
	public static String rexec(String cmd, String dir, int timeOut) {
		logger.debug(String.format("return cmd:[%s] timeout:[%s],path:[%s]", cmd, timeOut, dir));
		Process ps = null;
		BufferedReader br = null;
		StringBuilder result = new StringBuilder();
		try {
			ProcessBuilder pb = new ProcessBuilder(cmd.split(" "));
			pb.redirectErrorStream(true);
			if(null != dir){
				pb.directory(new File(dir));
			}
			ps = pb.start();
			addThreadMonitorTimeout(ps, timeOut);
			br = new BufferedReader(new InputStreamReader(ps.getInputStream(), "utf-8"));
			String line = null;
			while ((line = br.readLine()) != null) {
				if(StringUtils.isBlank(line.trim())){
					continue;
				}
				result.append(line.replaceAll("\\s+", " ").trim()).append("\n");
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			IOUtils.closeQuietly(br);
			if (ps != null) {
				ps.destroy();
			}
		}
		return result.toString();
	}
	
	/**
	 * 执行命令，不返回
	 * 
	 * @param cmd
	 */
	public static void exec(String cmd, int timeout) {
		exec(cmd, timeout, null);
	}
	
	/**
	 * 执行命令，不返回
	 * 
	 * @param cmd
	 */
	public static void execNoStream(String cmd) {
		logger.debug("master process stream " +cmd );
		try{
			Runtime.getRuntime().exec(cmd);
		}catch(Exception e){
			
		}
	}
	
	
	/**
	 * 执行命令，不返回
	 * 
	 * @param cmd
	 */
	public static void exec(String cmd) {
		exec(cmd, -1, null);
	}
	
	/**
	 * 执行命令，不返回结果
	 * @param cmd
	 * @param timeout
	 */
	public static void exec(String cmd, int timeout, String dir) {
		logger.debug(String.format("cmd:[%s] timeout:[%s],path:[%s]", cmd, timeout, dir));
		Process ps = null;
		try {
			if(dir == null){
				ps = Runtime.getRuntime().exec(cmd);
			}else{
				ps = Runtime.getRuntime().exec(cmd, null, new File(dir));
			}
			readSteam(ps);
			if(timeout == -1){
				ps.waitFor(2*60, TimeUnit.SECONDS);
			}else{
				ps.waitFor(timeout, TimeUnit.SECONDS);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			if(ps != null){
				if(ps.isAlive()){
					ps.destroy();
				}
			}
		}
	}


	/**
	 * 执行命令，并返回进程资源
	 * @param cmd
	 */
	public static Process execRetPro(String cmd) {
		Process p = null;
		try {
			p = Runtime.getRuntime().exec(cmd);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return p;
	}

	/**
	 * 格式化系统命令
	 * 
	 * @return
	 */
	public static String[] formatCmd(String cmd) {
		String osName = System.getProperty("os.name");
		if (osName.matches("(?i)windows.*")) {
			 return new String[]{"cmd","/c", cmd};
		}
		return new String[] { "/bin/bash", "-c", cmd };
	}

	/**
	 * 执行命令回显,用于ui界面显示
	 * 
	 * @param cmd
	 * @return
	 */
	public static void execAndShow(String cmd) {
		Process ps = null;
		BufferedReader br = null;
		try {
			String[] formatCmd = formatCmd(cmd);
			ProcessBuilder pb = new ProcessBuilder(formatCmd);
			pb.redirectErrorStream(true);
			ps = pb.start();
			br = new BufferedReader(new InputStreamReader(ps.getInputStream(), "utf-8"));
			String line = null;
			while ((line = br.readLine()) != null) {
				System.out.println(line);
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			IOUtils.closeQuietly(br);
			if (ps != null) {
				ps.destroy();
			}
		}
	}
	
	/**
	 * 监控线程等执行超时
	 * 
	 * @param timeout s(秒)
	 */
	public static void addThreadMonitorTimeout(Process process, int timeout) {
		ThreadManager.getInstance().start(()-> {
			long bTime = System.currentTimeMillis();
			while (true) {
				if(process == null){
					break;
				}
				if (process != null) {
					if (!process.isAlive()) {
						break;
					}
				}
				if (System.currentTimeMillis() - bTime > (timeout * 1000)) {
					break;
				}
				try {
					Thread.sleep(2 * 100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				
			}//end while
			if (process != null) {
				if (process.isAlive()) {
					process.destroy();
				}
			}
		});
	}
	
	/**
	 * 异步线程读取进程流，防止进程阻死
	 * @param ps
	 */
	public static void readSteam(Process ps){
		ThreadManager.getInstance().start(()-> {
			BufferedReader br = null;
			try {
				br = new BufferedReader(new InputStreamReader(ps.getInputStream(),"utf-8"));
				while (br.read() != -1) {
				}
			} catch (Exception e) {

			}finally{
				IOUtils.closeQuietly(br);
			}
		});
		ThreadManager.getInstance().start(()-> {
			BufferedReader br = null;
			try {
				br = new BufferedReader(new InputStreamReader(ps.getErrorStream(),"utf-8"));
				while (br.read() != -1) {
				}
			} catch (Exception e) {
				
			}finally{
				IOUtils.closeQuietly(br);
			}
		});
	}
	public static void main(String[] args) throws IOException {
		String path = "/home/ningruhu/raptor_result/monkey_test/833/2018-07-03-11.02.45/trident/memory_monitor";
		SystemCmdUtil.exec("bash report", 40, path);
	}

}
